#include <windows.h>
#include <windowsx.h>
#include <stdio.h>

#include "Game/Game.h"

#define TIMEOUT	(1000/FPS)
#define TIMERID	1

HINSTANCE hInst;			// current instance
HWND m_hWnd;
HDC			hDC=NULL;		// Private GDI Device Context
HGLRC		hRC=NULL;		// Permanent Rendering Context
HINSTANCE	hInstance;		// Holds The Instance Of The Application

Game * gme;

BOOL				InitInstance(HINSTANCE, int);
LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
void				DestroyScreen(void);
void				Init();
void				loop();
void				drawLake();
void				drawAxis();

int main(int argc, char* argv[]){
	WinMain(GetModuleHandle(NULL), NULL, NULL, SW_SHOW);
	return 1;
}

BOOL InitInstance(HINSTANCE hInstance,int nCmdShow){

	int width = SCREEN_WIDTH+2;
	int height = SCREEN_HEIGHT+2;

	WNDCLASS	wc;												// Windows Class Structure
	wc.style			= CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS;	// Redraw On Size, And Own DC For Window.
	wc.lpfnWndProc		= (WNDPROC) WndProc;					// WndProc Handles Messages
	wc.cbClsExtra		= 0;									// No Extra Window Data
	wc.cbWndExtra		= 0;									// No Extra Window Data
	wc.hInstance		= hInstance;							// Set The Instance
	wc.hIcon			= LoadIcon(NULL, IDI_WINLOGO);			// Load The Default Icon
	wc.hCursor			= LoadCursor(NULL, IDC_ARROW);			// Load The Arrow Pointer
	wc.hbrBackground	= NULL;									// No Background Required For GL
	wc.lpszMenuName		= NULL;									// We Don't Want A Menu
	wc.lpszClassName	= TEXT("OpenGL");					// Set The Class Name
	if (!RegisterClass(&wc)){									// Attempt To Register The Window Class
		MessageBox(NULL,TEXT("Failed To Register The Window Class."),TEXT("ERROR"),MB_OK|MB_ICONEXCLAMATION);
		return FALSE;											// Return FALSE
	}

	DWORD		dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;	// Window Extended Style
	DWORD		dwStyle=WS_OVERLAPPEDWINDOW;					// Window Style
	RECT		WindowRect;				// Grabs Rectangle Upper Left / Lower Right Values
	WindowRect.left=(long)0;			// Set Left Value To 0
	WindowRect.right=(long)width;		// Set Right Value To Requested Width
	WindowRect.top=(long)0;				// Set Top Value To 0
	WindowRect.bottom=(long)height;		// Set Bottom Value To Requested Height

	AdjustWindowRectEx(&WindowRect, WS_CAPTION|WS_SYSMENU, false, 0);
	m_hWnd=CreateWindowEx(	dwExStyle,							// Extended Style For The Window
								TEXT("OpenGL"),							// Class Name
								TEXT("opengltest"),								// Window Title
								dwStyle |							// Defined Window Style
								WS_CLIPSIBLINGS |					// Required Window Style
								WS_CLIPCHILDREN,					// Required Window Style
								SCREEN_WIDTH, SCREEN_HEIGHT,								// Window Position
								WindowRect.right-WindowRect.left,	// Calculate Window Width
								WindowRect.bottom-WindowRect.top,	// Calculate Window Height
								NULL,								// No Parent Window
								NULL,								// No Menu
								hInstance,							// Instance
								NULL);								// Dont Pass Anything To WM_CREATE

	if(!m_hWnd){
		//MessageBox(NULL,TEXT("Failed To create the window."),TEXT("ERROR"),MB_OK|MB_ICONEXCLAMATION);
		return false;
	}

	hDC = GetDC(m_hWnd);
	ShowWindow(m_hWnd, nCmdShow);
	UpdateWindow(m_hWnd);

	return true;
}


int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
	MSG msg;

	if (!InitInstance (hInstance, nCmdShow))
		return false;

	Init();

	// Main message loop:
	while (GetMessage(&msg, NULL, 0, 0)>0){
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}

/*-------------------------------------------------------------------*/
/*  Destroy screen                                         */
/*-------------------------------------------------------------------*/
void DestroyScreen()
{
	if (hRC) {										// Do We Have A Rendering Context?
		hRC=NULL;									// Set RC To NULL
	}

	if (hDC && !ReleaseDC(m_hWnd,hDC)) {			// Are We Able To Release The DC
		//MessageBox(NULL,TEXT("Release Device Context Failed."),TEXT("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
		hDC=NULL;										// Set DC To NULL
	}

	if (m_hWnd && !DestroyWindow(m_hWnd)) {			// Are We Able To Destroy The Window?
		//MessageBox(NULL,TEXT("Could Not Release hWnd."),TEXT("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
		m_hWnd=NULL;								// Set hWnd To NULL
	}

	if (!UnregisterClass(TEXT("OpenGL"),hInstance))	{// Are We Able To Unregister Class
		//MessageBox(NULL,TEXT("Could Not Unregister Class."),TEXT("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
		hInstance=NULL;									// Set hInstance To NULL
	}
}


int currentButton;
typedef struct{
	int x;
	int y;
} mousePoint;
mousePoint click;
bool isControlPressed=false;
bool tempbutton=false;

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{

	int clickcount=1;
	switch (message) 
	{
		case WM_CREATE:
			SetTimer(hWnd, TIMERID, TIMEOUT, NULL);
			break;
		case WM_DESTROY:
			delete(gme);
			KillTimer(hWnd, TIMERID);
			PostQuitMessage(0);
			break;
		case WM_TIMER:
			if(wParam == TIMERID){
				loop();
				//::eglWaitGL();
				SwapBuffers(hDC);
			}
			break;
		case WM_KEYDOWN:
			switch (wParam){
				case VK_ESCAPE:
					gme->hideNotify();
					break;
				case VK_F2:
					gme->showNotify();
					break;

			}
			break;
		case WM_KEYUP:
			break;
		case WM_LBUTTONDBLCLK:
			clickcount=2;
		case WM_LBUTTONDOWN:
			currentButton = message;
			gme->touchPressed(0, GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam),clickcount);
			break;

		case WM_MBUTTONDOWN:
			currentButton = message;
			click.x = GET_X_LPARAM(lParam); 
			click.y = GET_Y_LPARAM(lParam); 
			gme->getCamera()->cameraPosT=gme->getCamera()->cameraPos;
			gme->getCamera()->cameraObjetivePosT=gme->getCamera()->cameraObjetivePos;
			
			break;
		case WM_LBUTTONUP:
			switch(currentButton){
				case WM_LBUTTONDOWN:
					gme->touchReleased(0, GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam));
					break;
				case WM_RBUTTONDOWN:
					gme->touchReleased(1, GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam));
					break;
			}
			currentButton=0;
			break;
		case WM_RBUTTONUP:
		case WM_MBUTTONUP:
			currentButton=0;
			break;
		case WM_MOUSEMOVE:
			
			switch(currentButton){
				case WM_LBUTTONDOWN:
					gme->touchMoved(0 , GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam));
					break;
				case WM_RBUTTONDOWN:
					gme->touchMoved(1 , GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam));
					break;
				
				case WM_MBUTTONDOWN:
					int x=0,y=0;
					mousePoint currPoint;
					
					currPoint.x = GET_X_LPARAM(lParam); 
					currPoint.y = GET_Y_LPARAM(lParam); 
					x=currPoint.x-click.x;
					y=currPoint.y-click.y;
					
					gme->getCamera()->cameraPos = Vec3f::rotate(gme->getCamera()->cameraPosT,Vec3f(0.0f,0.0f,1.0f),x);
					gme->getCamera()->cameraPos = Vec3f::rotate(gme->getCamera()->cameraPos,Vec3f(1.0f,0.0f,0.0f),y);
					
					break;
					
			}
			break;
		case WM_MOUSEWHEEL:
			int zDelta;
			zDelta = GET_WHEEL_DELTA_WPARAM(wParam)/WHEEL_DELTA;
			gme->getCamera()->cameraPos+=Vec3f(0.0f,zDelta*8,0.0f);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
   }
   return 0;
}


void Init(){
	gme = new Game(hDC,m_hWnd);	
}

void loop(){
	gme->paint();
	gme->update();
}
